/*
 * Sprite.cpp
 *
 *  Created on: 15/11/2011
 *      Author: Tales
 */

#include "Sprite.hpp"
#include <SDL_image.h>
#include "../Error.hpp"
#include "Canvas.hpp"

namespace yep
{
Uint32 Sprite::_worldFrame = 0;

Sint16 Sprite::getIndex(void) const
{
	return (_offset + int(_worldFrame * velocity)) % nframes;
}

void Sprite::draw(Canvas &canvas, const Vector2 &position)
{
	Sint16 index = (_offset + int(_worldFrame * velocity)) % nframes;
	Sint16 line = index / ncols;
	Sint16 collumn = index % ncols;

	SDL_Rect slice =
	{ Sint16(collumn * width), Sint16(line * height), width, height };
	SDL_BlitSurface(surface, &slice, canvas.getSurface(), position);
}

void Sprite::draw(Canvas &canvas, const Vector2 &position, const Vector2 &sectionPosition, const Vector2 &sectionSize)
{
	Sint16 index = (_offset + int(_worldFrame * velocity)) % nframes;
	Sint16 line = index / ncols;
	Sint16 collumn = index % ncols;

	SDL_Rect slice =
	{ Sint16(collumn * width + sectionPosition.x), Sint16(line * height + sectionPosition.x), min(width,
			(Uint16) sectionSize.x), min(height, (Uint16) sectionSize.y) };
	SDL_BlitSurface(surface, &slice, canvas.getSurface(), position);
}

void Sprite::setLocalOffset(unsigned value)
{
	_offset = value % nframes;
}
unsigned Sprite::getLocalOffset() const
{
	return _offset;
}

void Sprite::setVelocity(double vel)
{
	velocity = vel;
}

double Sprite::getVelocity() const
{
	return velocity;
}

Sprite::Sprite(const char *imageFile, int width_, int height_)
{
	surface = IMG_Load(imageFile);
	if (!surface)
		YEP_ERROR((string("Can't open image '")+ imageFile+"'").c_str());
	width = width_;
	height = height_;
	velocity = 1;
	ncols = (surface->w / width_);
	nframes = (surface->w / width_) * (surface->h / height_);
	int gframe = _worldFrame;
	setLocalOffset(((gframe / nframes) + 1) * nframes - gframe);
}

Sprite::~Sprite()
{
	SDL_FreeSurface(surface);
}

SDL_Surface* Sprite::getSurface()
{
	return surface;
}

Sprite::Sprite(const Sprite &other)
{
	rawCopy(other);
	++surface->refcount;
}

Sprite &Sprite::operator=(const Sprite &other)
{
	// check for assignment to self
	if (this == &other)
		return *this;
	SDL_FreeSurface(surface);
	rawCopy(other);
	++surface->refcount;
	return *this;
}

void Sprite::rawCopy(const Sprite &other)
{
	_offset = other._offset;
	velocity = other.velocity;
	surface = other.surface;
	ncols = other.ncols;
	nframes = other.nframes;
	width = other.width;
	height = other.height;
}

bool Sprite::transparent(unsigned line, unsigned col) const
{
	SDL_PixelFormat &format = *surface->format;
	Uint32 pixel = 0;
	Uint8 Bpp = format.BytesPerPixel;
	Rect myArea = Rect();
	Uint8 *ptr = ((Uint8*) surface->pixels) + (line + myArea.y()) * (col + myArea.x()) * Bpp;
	for (int i = 0; i < Bpp; ++i)
		pixel |= (Uint32) (ptr[i]) << 8 * i;
	if (format.Amask)
	{
		Uint8 r, g, b, a;
		SDL_GetRGBA(pixel, &format, &r, &g, &b, &a);
		return !(a & 80);
	}
	else
	{
		return pixel == format.colorkey;
	}
}

}

